import { Component, lazy as solidLazy } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { getManifest } from "solid-start:get-manifest";
import { useAssets } from "../server/assets/index.ts";
import { Asset, PageEvent } from "../server/types.ts";

const assetsById: Record<string, Asset[]> = {};

const getAssets = async (id: string) => {
  if (assetsById[id]) return assetsById[id];

  const manifest = getManifest(import.meta.env.SSR && import.meta.env.DEV ? "ssr" : "client");
  const assets = await manifest.getAssets(id);
  if (import.meta.env.PROD) assetsById[id] = assets;

  return assets;
};

const withAssets = function <T extends () => Promise<{ default: Component<any> }>>(fn: T): T {
  const wrapper = async () => {
    const mod = await fn();

    // This id$$ export is generated by the lazy vite plugin
    const id: string = (mod as any).id$$;
    if (!id) return mod;

    if (!mod.default) {
      console.error(`Module ${id} does not export default`);
      return { default: () => [] };
    }

    const assets: Asset[] = await getAssets(id);
    if (!assets.length) return mod;

    return {
      default: (props: any) => {
        const { nonce } = getRequestEvent() as PageEvent;
        useAssets(assets, nonce);

        return mod.default(props);
      }
    };
  };

  return wrapper as T;
};

const lazy = !isServer ? solidLazy: <T extends Component<any>>(fn: () => Promise<{ default: T }>) =>
  solidLazy(withAssets(fn));

export default lazy;
